using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using HslCommunication;

namespace Catastrophe.AutoSulution.TaskM
{
	public class ScheduleControl<T> : IScheduleControl where T : BaseLogic
	{
		/// <summary>
		/// 调度循环任务
		/// </summary>
		private Task _controlTask;

		/// <summary>
		/// 线程同步事件
		/// </summary>
		private ManualResetEvent _manualReset;

		/// <summary>
		///     类型T标记方法集合
		/// </summary>
		private List<MethodInfo> _methodInfoList = new List<MethodInfo>();

		/// <summary>
		/// 任务循环启动标识
		/// </summary>
		private bool _runContinue = true;

		/// <summary>
		/// 当前正在执行的任务（执行完成以后赋值）
		/// </summary>
		private TaskComplete _taskCompleteNow;

		/// <summary>
		/// 当前正在执行的方法信息，执行之前判断
		/// </summary>
		private ScheduleMethodInfo _scheduleMethodInfoNow;

		/// <summary>
		/// 剩余超时时间
		/// </summary>
		private long _remainTimeOut;

		/// <summary>
		/// 是否是阻塞状态
		/// </summary>
		public bool _isBlock;

		/// <summary>
		/// 任务信息
		/// </summary>
		private List<ScheduleMethodInfo> _scheduleMethodList;

		/// <summary>
		///     控制流程提示(每次执行方法的时候触发)
		/// </summary>
		public Action<TaskComplete> ControlStepHandler { get; set; }

		/// <summary>
		/// 执行完成、执行成功以后更新步骤值
		/// </summary>
		public Action<int> TaskStepMonitorHandler { get; set; }

		public TaskComplete TaskCompleteNow => this._taskCompleteNow;

		public ScheduleMethodInfo ScheduleMethodInfoNow => this._scheduleMethodInfoNow;

		/// <summary>
		///     等待执行完成超时
		/// </summary>
		public Action<TaskComplete> WaitTimeOutHandler { get; set; }

		/// <summary>
		/// 超时的默认设定值
		/// </summary>
		public long TimeOutDefault { get; set; } = 15000000L;


		/// <summary>
		///     等待执行完成循环周期时间
		/// </summary>
		public int WaitCompleteInerval { get; set; } = 30;


		/// <summary>
		///     执行方法间隔
		/// </summary>
		public int ExcuteInterval { get; set; } = 30;


		/// <summary>
		///     是否检测等待超时
		/// </summary>
		public bool CheckWaitTimeOut { get; set; }

		/// <summary>
		///     T实例对象
		/// </summary>
		public T Tinstance { get; set; }

		public object Instance => this.Tinstance;

		/// <summary>
		/// 加载Ini方法之前调用
		/// </summary>
		public Action<T> LoadIniHandler { get; set; }

		/// <summary>
		/// 执行线程释放完成委托
		/// </summary>
		public Action DisposedHandler { get; set; }

		/// <summary>
		/// 暂停
		/// </summary>
		public Action StopHandler { get; set; }

		public bool IsBlock => this._isBlock;

		/// <summary>
		/// 剩余超时时间
		/// </summary>
		public long RemainTimeOut => this._remainTimeOut / 1000;

		/// <summary>
		/// 最大步骤(实际调度任务数量，实际情况不一定所有任务都参与)-进度最大值
		/// </summary>
		public int MaxStep => this._scheduleMethodList?.Count ?? 0;

		/// <summary>
		/// 调度是否完成
		/// </summary>
		[Obsolete("use IsStarted instead")]
		public bool? IsCompleted => this._controlTask?.IsCompleted;

		/// <summary>
		/// 是否启动
		/// </summary>
		public bool IsStarted
		{
			get
			{
				Task controlTask = this._controlTask;
				return controlTask != null && !controlTask.IsCompleted;
			}
		}

		/// <summary>
		/// 调度名称，在多个设备使用同一个调度逻辑情况下作为不同设备判断依据
		/// </summary>
		public string Name { get; set; }

		/// <summary>
		/// 是否任务结束
		/// </summary>
		public bool IsFinished
		{
			get
			{
				if (this._controlTask == null)
				{
					return true;
				}
				return this._controlTask.IsCompleted;
			}
		}

		public ScheduleControl()
		{
			Type typeFromHandle = typeof(T);
			this.Tinstance = Activator.CreateInstance(typeFromHandle) as T;
			this._methodInfoList = typeFromHandle.GetMethods().ToList();
		}

		/// <summary>
		///     异步启动
		/// </summary>
		public void Start()
		{
			if (this._controlTask == null)
			{
				Type typeFromHandle = typeof(T);
				if (this.Tinstance == null)
				{
					this.Tinstance = (T)Activator.CreateInstance(typeFromHandle);
				}
				BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic;
				List<MethodInfo> list = (from x in typeFromHandle.GetMethods(bindingAttr)
					where x.Name == "Ini"
					select x).ToList();
				if (list.Count > 0)
				{
					this.LoadIniHandler?.Invoke(this.Tinstance);
					list[0].Invoke(this.Tinstance, null);
				}
				this._runContinue = true;
				this._controlTask = Task.Run(new Action(Excute));
			}
		}

		/// <summary>
		/// 任务挂起
		/// </summary>
		private void TaskSuspend()
		{
			try
			{
				if (this._isBlock)
				{
					this.StopHandler?.Invoke();
				}
			}
			finally
			{
				this._manualReset?.WaitOne();
			}
		}

		/// <summary>
		///     执行顺序逻辑控制
		/// </summary>
		private void Excute()
		{
			this._scheduleMethodList = (from x in this._methodInfoList
				select new
				{
					MethodInfo = x,
					Attribute = (Attribute.GetCustomAttribute(x, typeof(ScheduleAttribute)) as ScheduleAttribute)
				} into y
				where y.Attribute != null && !y.Attribute.Ignore
				orderby y.Attribute.Index
				select y into x
				select new ScheduleMethodInfo
				{
					MethodInfo = x.MethodInfo,
					Attribute = x.Attribute,
					FuncMethod = (Func<TaskComplete, TaskComplete>)Delegate.CreateDelegate(typeof(Func<TaskComplete, TaskComplete>), this.Tinstance, x.MethodInfo)
				}).ToList();
			this._manualReset = new ManualResetEvent(initialState: true);
			Stopwatch stopwatch = new Stopwatch();
			bool flag = false;
			TaskComplete result = null;
			bool flag2 = false;
			bool flag3 = true;
			while (this._runContinue)
			{
				flag3 = true;
				if (this._scheduleMethodList.Count == 0)
				{
					Thread.Sleep(this.ExcuteInterval);
					break;
				}
				foreach (ScheduleMethodInfo scheduleMethod in this._scheduleMethodList)
				{
					this.TaskSuspend();
					if (!this._runContinue || flag)
					{
						flag = false;
						break;
					}
					if (flag2)
					{
						if (!this._scheduleMethodList.Any((ScheduleMethodInfo x) => x.MethodInfo.Name.Equals(result.DstFunc?.Method.Name)))
						{
							throw new Exception("目标方法不存在" + result.DstFunc?.Method.Name);
						}
						if (!scheduleMethod.MethodInfo.Name.Equals(result.DstFunc?.Method.Name))
						{
							continue;
						}
						flag2 = false;
						result.DstFunc = null;
					}
					long num = ((scheduleMethod.Attribute.TimeOut < 0) ? this.TimeOutDefault : scheduleMethod.Attribute.TimeOut);
					long num2 = 0L;
					result = this.ExcuteSingle(scheduleMethod, result);
					if (result.RunStatus == RunStatusEnum.Stop)
					{
						this.Stop();
						continue;
					}
					if (result.RunStatus == RunStatusEnum.Break)
					{
						flag2 = result.DstFunc != null;
						break;
					}
					if (result.RunStatus == RunStatusEnum.Finished)
					{
						this.Dispose();
						break;
					}
					while (this._runContinue && result.RunStatus == RunStatusEnum.Wait)
					{
						this.TaskSuspend();
						if (!this._runContinue)
						{
							break;
						}
						if (this.CheckWaitTimeOut)
						{
							stopwatch.Reset();
							stopwatch.Start();
						}
						result = this.ExcuteSingle(scheduleMethod, result);
						Thread.Sleep(this.WaitCompleteInerval);
						flag3 = false;
						if (this.CheckWaitTimeOut)
						{
							stopwatch.Stop();
							num2 += stopwatch.ElapsedMilliseconds;
							this._remainTimeOut = this.TimeOutDefault - num2;
							if (num2 >= num)
							{
								this.WaitTimeOutHandler?.Invoke(result);
								this.Dispose();
								break;
							}
						}
						else
						{
							this._remainTimeOut = 0L;
							num2 = 0L;
						}
						if (result.RunStatus == RunStatusEnum.Stop)
						{
							this.Stop();
							continue;
						}
						if (result.RunStatus == RunStatusEnum.Break)
						{
							flag2 = result.DstFunc != null;
							flag = true;
							break;
						}
						if (result.RunStatus != RunStatusEnum.Finished)
						{
							continue;
						}
						this.Dispose();
						flag = true;
						break;
					}
					if (flag3)
					{
						Thread.Sleep(this.ExcuteInterval);
					}
				}
			}
		}

		/// <summary>
		/// 执行之前
		/// </summary>
		/// <param name="methodInfo"></param>
		private void BeforeExucte(ScheduleMethodInfo methodInfo)
		{
			this.Tinstance.WaitInfo = "";
			this.Tinstance.ConditionValue = "";
			this.Tinstance.ExcuteMehtodChanged();
		}

		/// <summary>
		///     调用单个方法委托
		/// </summary>
		/// <param name="value"></param>
		/// <param name="taskResult"></param>
		/// <returns></returns>
		private TaskComplete ExcuteSingle(ScheduleMethodInfo value, TaskComplete taskResult)
		{
			ScheduleMethodInfo scheduleMethodInfoNow = this._scheduleMethodInfoNow;
			if (scheduleMethodInfoNow == null || !scheduleMethodInfoNow.Equals(value))
			{
				this._scheduleMethodInfoNow = value;
				this.ExcuteMehtodChanged(value, taskResult);
			}
			TaskComplete taskComplete = null;
			try
			{
				this.Tinstance.BeforeExcute(value, taskResult);
				taskComplete = value.FuncMethod(taskResult);
				if (taskComplete.OprResult.IsSuccess)
				{
					this.TaskStepMonitorHandler?.Invoke(taskComplete.ProcessValue);
				}
				taskComplete.ScheduleAb = value.Attribute;
				taskComplete.MethodName = value.MethodInfo.Name;
				return taskComplete;
			}
			catch (Exception exception)
			{
				taskComplete = new TaskComplete
				{
					RunStatus = RunStatusEnum.Wait,
					Exception = exception,
					Flag = taskResult?.Flag,
					ScheduleAb = value.Attribute,
					Param = taskResult?.Param,
					TaskStepDetails = taskResult?.TaskStepDetails
				};
				return taskComplete;
			}
			finally
			{
				this._taskCompleteNow = taskComplete;
				this.Tinstance.AfterExcute(value, taskResult);
				this.ControlStepHandler?.Invoke(taskComplete);
			}
		}

		/// <summary>
		/// 执行方法发生了改变
		/// 1.OperateResult要初始化，不能承接上次的成功结果
		/// </summary>
		private void ExcuteMehtodChanged(ScheduleMethodInfo scheMethodInfo, TaskComplete taskComplete)
		{
			this.BeforeExucte(scheMethodInfo);
			if (taskComplete != null)
			{
				taskComplete.OprResult = new OperateResult
				{
					Message = ""
				};
			}
		}

		/// <summary>
		///    释放-取消运行标识，不会立即完成，完成以后回调DisposedHandler
		/// </summary>
		public void Dispose()
		{
			this._runContinue = false;
			if (this._isBlock)
			{
				this.Continue();
			}
			this._manualReset = null;
			Task.Run(new Action(DisposeHandler));
		}

		/// <summary>
		///     手动释放-取消运行标识并等待线程结束
		/// </summary>
		public void DisposeWait()
		{
			if (this._controlTask == null)
			{
				return;
			}
			this.Dispose();
			while (true)
			{
				Task controlTask = this._controlTask;
				if (controlTask == null || controlTask.IsCompleted)
				{
					break;
				}
				Thread.Sleep(20);
			}
			this._controlTask = null;
		}

		/// <summary>
		/// 等待完成，触发事件
		/// </summary>
		private void DisposeHandler()
		{
			if (this._controlTask == null)
			{
				return;
			}
			while (true)
			{
				Task controlTask = this._controlTask;
				if (controlTask == null || controlTask.IsCompleted)
				{
					break;
				}
				Thread.Sleep(20);
			}
			this._controlTask = null;
			this.DisposedHandler?.Invoke();
		}

		/// <summary>
		///     暂停-执行一个完整周期以后
		/// </summary>
		public void Stop()
		{
			this._isBlock = true;
			this._manualReset?.Reset();
		}

		/// <summary>
		///     继续执行
		/// </summary>
		public void Continue()
		{
			this._isBlock = false;
			this._manualReset?.Set();
		}

		/// <summary>
		/// 获取方法的描述信息
		/// </summary>
		/// <param name="funcMethod"></param>
		/// <returns></returns>
		public ScheduleAttribute GetMethodDescribe(Func<TaskComplete, TaskComplete> funcMethod)
		{
			return this._scheduleMethodList?.Where((ScheduleMethodInfo x) => x.FuncMethod == funcMethod).FirstOrDefault()?.Attribute;
		}

		/// <summary>
		/// 获取步骤的索引值
		/// </summary>
		/// <param name="funcMethod"></param>
		/// <returns></returns>
		public int StepIndexNow(Func<TaskComplete, TaskComplete> funcMethod)
		{
			return this._scheduleMethodList.FindIndex((ScheduleMethodInfo x) => x.FuncMethod == funcMethod) + 1;
		}

		/// <summary>
		/// 获取步骤的索引值
		/// </summary>
		/// <param name="methodName"></param>
		/// <returns></returns>
		public int StepIndexNow(string methodName)
		{
			return this._scheduleMethodList.FindIndex((ScheduleMethodInfo x) => x.MethodInfo.Name == methodName) + 1;
		}

		/// <summary>
		/// 清空超时时间
		/// </summary>
		public void ClearTimeOut()
		{
			this._remainTimeOut = 0L;
		}
	}
}
